import React, { useState, useMemo, useCallback, useEffect } from 'react';

// 子组件 - 用于演示 useCallback 的优化效果
interface ExpensiveChildProps {
  onClick: () => void;
  data: number[];
}

const ExpensiveChild: React.FC<ExpensiveChildProps> = React.memo(({ onClick, data }) => {
  console.log('ExpensiveChild 重新渲染了！');
  
  return (
    <div className="demo-section">
      <h3>子组件（ExpensiveChild）</h3>
      <p>这个组件使用了 React.memo 进行优化</p>
      <p>当前数据: {data.join(', ')}</p>
      <button onClick={onClick}>调用父组件回调</button>
    </div>
  );
});

// 另一个子组件 - 用于演示 useMemo 的优化
interface DataDisplayProps {
  data: number[];
  filter: string;
}

const DataDisplay: React.FC<DataDisplayProps> = React.memo(({ data, filter }) => {
  console.log('DataDisplay 重新渲染了！');
  
  const filteredData = useMemo(() => {
    console.log('重新计算过滤后的数据...');
    return data.filter(item => item.toString().includes(filter));
  }, [data, filter]);
  
  return (
    <div className="demo-section">
      <h3>数据展示组件（DataDisplay）</h3>
      <p>过滤后的数据: {filteredData.join(', ') || '无匹配数据'}</p>
    </div>
  );
});

const UseMemoCallbackDemo: React.FC = () => {
  const [count, setCount] = useState(0);
  const [numbers, setNumbers] = useState<number[]>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  const [filter, setFilter] = useState('');
  const [name, setName] = useState('');

  // 使用 useMemo 计算复杂计算
  const expensiveCalculation = useMemo(() => {
    console.log('执行复杂计算...');
    return numbers.reduce((sum, num) => sum + num * num, 0);
  }, [numbers]);

  // 使用 useMemo 过滤数据
  const filteredNumbers = useMemo(() => {
    console.log('过滤数据...');
    return numbers.filter(num => num % 2 === 0);
  }, [numbers]);

  // 使用 useCallback 优化回调函数
  const handleChildClick = useCallback(() => {
    console.log('子组件点击了！');
    setCount(prev => prev + 1);
  }, []);

  // 未使用 useCallback 的回调（每次渲染都会重新创建）
  const handleChildClickWithoutMemo = () => {
    console.log('未优化的回调被调用了！');
    setCount(prev => prev + 1);
  };

  // 添加数字
  const addNumber = () => {
    const newNum = Math.floor(Math.random() * 100) + 1;
    setNumbers(prev => [...prev, newNum]);
  };

  // 移除最后一个数字
  const removeNumber = () => {
    setNumbers(prev => prev.slice(0, -1));
  };

  return (
    <div className="demo-page">
      <h1>useMemo 和 useCallback Hook</h1>
      <p className="description">
        学习如何使用 useMemo 和 useCallback 优化 React 应用的性能
      </p>

      {/* useMemo 示例 */}
      <div className="demo-section">
        <h2>useMemo 示例</h2>
        <p>
          useMemo 用于缓存计算结果，避免在每次渲染时重复执行昂贵的计算。
        </p>
        
        <div className="counter-demo">
          <p>当前数字: {count}</p>
          <div className="button-group">
            <button onClick={() => setCount(count + 1)}>增加计数</button>
            <button onClick={addNumber}>添加随机数字</button>
            <button onClick={removeNumber}>移除最后一个数字</button>
          </div>
        </div>

        <div style={{ marginTop: '2rem' }}>
          <h3>计算结果（使用 useMemo 缓存）</h3>
          <p>数字平方和: {expensiveCalculation}</p>
          <p>偶数列表: {filteredNumbers.join(', ')}</p>
          <p className="note">
            💡 注意：只有 numbers 数组改变时才会重新计算
          </p>
        </div>
      </div>

      {/* useCallback 示例 */}
      <div className="demo-section">
        <h2>useCallback 示例</h2>
        <p>
          useCallback 用于缓存函数引用，避免在每次渲染时创建新的函数实例。
        </p>
        
        <div className="comparison">
          <div className="comparison-item">
            <h3>使用 useCallback 优化</h3>
            <ExpensiveChild 
              onClick={handleChildClick} 
              data={numbers} 
            />
            <p className="note">
              ✅ 子组件不会因为父组件的无关状态变化而重新渲染
            </p>
          </div>
          
          <div className="comparison-item">
            <h3>未使用 useCallback</h3>
            <ExpensiveChild 
              onClick={handleChildClickWithoutMemo} 
              data={numbers} 
            />
            <p className="note">
              ⚠️ 每次父组件渲染时都会创建新的回调函数，导致子组件重新渲染
            </p>
          </div>
        </div>
      </div>

      {/* useMemo 过滤数据示例 */}
      <div className="demo-section">
        <h2>useMemo 过滤数据示例</h2>
        <div>
          <label>过滤条件：</label>
          <input
            type="text"
            value={filter}
            onChange={(e) => setFilter(e.target.value)}
            placeholder="输入过滤条件"
          />
        </div>
        <DataDisplay data={numbers} filter={filter} />
      </div>

      {/* 实际应用场景 */}
      <div className="demo-section">
        <h2>实际应用场景</h2>
        
        <div className="best-practices">
          <div className="practice-item">
            <h3>useMemo 使用场景</h3>
            <ul>
              <li>复杂计算的结果（如：排序、过滤、聚合）</li>
              <li>昂贵的对象创建（如：图表配置、大型对象）</li>
              <li>避免在渲染方法中重复计算</li>
            </ul>
          </div>
          
          <div className="practice-item">
            <h3>useCallback 使用场景</h3>
            <ul>
              <li>传递给子组件的回调函数</li>
              <li>作为 useEffect 的依赖项</li>
              <li>需要保持引用稳定的函数</li>
            </ul>
          </div>
          
          <div className="practice-item">
            <h3>注意事项</h3>
            <ul>
              <li>不是所有情况都需要使用 - 过度优化可能适得其反</li>
              <li>只有当计算或函数确实昂贵时才使用</li>
              <li>使用 React.memo 配合 useCallback 效果更好</li>
              <li>依赖数组要正确设置，避免遗漏依赖</li>
            </ul>
          </div>
        </div>
      </div>

      {/* 代码示例 */}
      <div className="demo-section">
        <h2>代码示例</h2>
        
        <div className="code-example">
          <h3>useMemo 示例</h3>
          <pre>{`const expensiveValue = useMemo(() => {
  // 昂贵的计算
  return items.reduce((total, item) => total + item.price, 0);
}, [items]); // 只在 items 改变时重新计算`}</pre>
        </div>

        <div className="code-example">
          <h3>useCallback 示例</h3>
          <pre>{`const handleClick = useCallback(() => {
  // 回调函数
  setCount(prev => prev + 1);
}, []); // 空依赖数组，函数引用不会改变`}</pre>
        </div>
      </div>
    </div>
  );
};

export default UseMemoCallbackDemo;